﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using linq = Microsoft.Linq.Expressions;
using System.Linq;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using Bling.Util;

// focus on this class in making generic.

namespace Bling.DSL {
  public partial class BoolBl : CoreBl<bool, BoolBl> {
    public PointBl Condition(PointBl ifTrue, PointBl ifFalse) {
      return Expr<Point>.ConditionOp.Make(this, ifTrue, ifFalse).Bl();
    }
    public ColorBl Condition(ColorBl ifTrue, ColorBl ifFalse) {
      return Expr<Color>.ConditionOp.Make(this, ifTrue, ifFalse).Bl();
    }
    public Point3DBl Condition(Point3DBl ifTrue, Point3DBl ifFalse) {
      return Expr<Point3D>.ConditionOp.Make(this, ifTrue, ifFalse).Bl();
    }
    public BrushBl Condition(BrushBl ifTrue, BrushBl ifFalse) {
      return Expr<Brush>.ConditionOp.Make(this, ifTrue, ifFalse).Bl();
    }
  }
  public partial class StringBl : Brand<string, StringBl> {
    public static implicit operator StringBl(Point s) { return s.Bl(); }
    public static implicit operator StringBl(Color s) { return s.Bl(); }
  }
  public partial class DoubleBl : ScalarBlValue<double, DoubleBl, DoubleArity> {
    public static ColorBl operator *(Color c, DoubleBl d) {
      return (Operations.Make(c)).Bl() * d;
    }
    public static PointBl operator *(Point c, DoubleBl d) {
      return (Operations.Make(c)).Bl() * d;
    }
    public static ColorBl operator /(Color c, DoubleBl d) {
      return (Operations.Make(c)).Bl() / d;
    }
    public static PointBl operator /(Point c, DoubleBl d) {
      return (Operations.Make(c)).Bl() / d;
    }
  }
  public abstract partial class BrushBl<T, BRAND> : Brand<T, BRAND>
    where T : Brush
    where BRAND : BrushBl<T, BRAND> {
    public BrushBl(Expr<T> Underlying) : base(Underlying) { }
    /// <summary>
    /// Samples a pbrush as a 2D texture inside a pixel shader.
    /// </summary>
    /// <param name="X">x coordinate of pixel to be sampled.</param>
    /// <param name="Y">y coordinate of pixel to be sampled.</param>
    /// <returns>Color of sampled pixel.</returns>
    /// <remarks>Works only in pixel shaders.</remarks>
    public ColorBl this[DoubleBl X, DoubleBl Y] {
      get { return this[new PointBl(X, Y)]; }
    }
    protected static Operator<Brush, Point, Color> Tex2DOp = new Operator<Brush, Point, Color>(Markers.Tex2DMarker) { };

    /// <summary>
    /// Samples the brush as a 2D texture inside a pixel shader. 
    /// </summary>
    /// <param name="point">Percentage point of the sample.</param>
    /// <returns>Color of pixel sampled.</returns>
    /// <remarks>Will only work inside pixel shaders.</remarks>
    public ColorBl this[PointBl point] {
      get { return Tex2DOp.Make(BrushBl.UpCast<T>(Underlying), point); }
    }
  }

  public partial class BrushBl : BrushBl<Brush, BrushBl> {
    public BrushBl(Expr<Brush> Underlying) : base(Underlying) { }
    static BrushBl() {
      Register(v => (v));
    }
    public new static BrushBl UpCast<S>(Expr<S> value) where S : Brush {
      return BrushBl<Brush, BrushBl>.UpCast<S>(value);
    }

    public static implicit operator BrushBl(Expr<Brush> v) { return new BrushBl(v); }
    public static implicit operator BrushBl(Brush v) { return Operations.Make(v); }
    //public static implicit operator BrushBl(Color c) { return new SolidColorBrush() { Color = c }; }
  }
  public abstract partial class AngleBl<BRAND> : AddBl<double, BRAND> where BRAND : AngleBl<BRAND> {
    protected static readonly Operator<double, Point> SinCosOp = new Operator<double, Point>(Markers.SinCosMarker) {
      Expand = (a) => new PointBl(SinOp.Make(a), CosOp.Make(a)),
      Inverse = (p) => p.Bl().Angle.Inverse
    };
    /// <summary>
    /// Returns a point around origin that is a unit vector for this angle.
    /// </summary>
    public PointBl ToPoint() { return SinCosOp.Make((2d * Math.PI - Radians) + .5d * Math.PI); }

    /// <summary>
    /// reutrn the angle between the line(p0,(0,0)) and the horizontal line
    /// </summary>
    /// <param name="p0">the vertex to form the angle with the horizontal line</param>
    /// <returns></returns>
    public static RadianAngleBl Angle(PointBl p0) { return AngleBetween(new Point(1, 0), p0); }
  }
  public partial class PointArity : ArityInfo<Point, PointArity> {
    public override int Arity {
      get { return 2; }
    }
    public override double[] ToArray(Point t) {
      return new double[] { t.X, t.Y };
    }
    public override Point ToT(double[] values) {
      return new Point(values[0], values[1]);
    }
    public override Expr<double> Access(Expr<Point> value, int idx) {
      return value.Bl()[idx];
    }
    public override string[] AccessorNames {
      get { return new string[] { "X", "Y", }; }
    }
  }
  /// <summary>
  /// Represents an x- and y-coordinate pair in two-dimensional space.
  /// </summary>
  public partial class PointBl : PointBl<Point, PointBl, PointArity> {
    public static implicit operator PointBl(Point d) { return new PointBl(Operations.Make(d)); }
    public static implicit operator PointBl(Vector d) { return new PointBl(Operations.Make((Point)d)); }
    public static implicit operator PointBl(Expr<Vector> d) { return PointBl.ExplicitConvert(d); }
    public static implicit operator PointBl(Expr<Size> d) { return PointBl.ExplicitConvert(d); }

    private PointBl(Expr<Point> Underlying) : base(Underlying) { }
    public PointBl(DoubleBl X, DoubleBl Y) : base(PointArity.ArityExpr.Make(X, Y)) { }
    public static implicit operator PointBl(Random r) {
      return (PointBl)((TupleBl<Point, PointBl, PointArity>)r);
    }
    public override PointBl XY {
      get { return this; }
      set { XY.Bind = value; }
    }

    /// <summary>
    /// X/horizontal component of point.
    /// </summary>
    public DoubleBl X {
      get { return this[0]; }
      set { X.Bind = value; }
    }
    /// <summary>
    /// Y/vertical component of point.
    /// </summary>
    public DoubleBl Y {
      get { return this[1]; }
      set { Y.Bind = value; }
    }
    /// <summary>
    /// A point whose both components are NaN.
    /// </summary>
    public static PointBl NaN {
      get { return new PointBl(double.NaN, double.NaN); }
    }

    static PointBl() {
      VectorType = typeof(Vector);

      Plus.Apply = (x, y) => x + ((Vector)y);
      Minus.Apply = (x, y) => x - ((Vector)y);
      MultiplyX.Apply = (x, y) => (Point)(((Vector)x) * y);
      DivideX.Apply = (x, y) => (Point)(((Vector)x) / y);
      Multiply.Apply = (p, q) => new Point(p.X * q.X, p.Y * q.Y);
      Divide.Apply = (p, q) => new Point(p.X / q.X, p.Y / q.Y);
      LengthOp.Apply = (p) => ((Vector)p).Length;
      Register(v => new PointBl(v));

      if (true) {
        DivideX.AsText = (a, b) => {
          var Type = typeof(Point).FullName;
          return ("new " + Type + "(" +
            a + ".X / " + b + ", " +
            a + ".Y / " + b + ")");
        };
        MultiplyX.AsText = (a, b) => {
          var Type = typeof(Point).FullName;
          return ("new " + Type + "(" +
            a + ".X * " + b + ", " +
            a + ".Y * " + b + ")");
        };
        Plus.AsText = (a, b) => {
          var Type = typeof(Point).FullName;
          return ("new " + Type + "(" +
            a + ".X + " + b + ".X, " +
            a + ".Y + " + b + ".Y)");
        };
      }

    }
    public static Point Plus0(Point p, double d) { return p + new Vector(d, d); }
    public static Point Minus0(Point p, double d) { return p - new Vector(d, d); }
    public static Point Mult(Point p0, Point p1) { return new Point(p0.X * p1.X, p0.Y * p1.Y); }
    public static Point Div(Point p0, Point p1) { return new Point(p0.X / p1.X, p0.Y / p1.Y); }
    public static Point Mod0(Point p0, Point p1) { return new Point(p0.X % p1.X, p0.Y % p1.Y); }

    public static implicit operator PointBl(Expr<Point> v) { return new PointBl(v); }
  }
  public partial class Point3DArity : ArityInfo<Point3D, Point3DArity> {
    public override string[] AccessorNames {
      get { return new string[] { "X", "Y", "Z", }; }
    }
    public override int Arity {
      get { return 3; }
    }
    public override double[] ToArray(Point3D t) {
      return new double[] { t.X, t.Y, t.Z };
    }
    public override Point3D ToT(double[] values) {
      return new Point3D(values[0], values[1], values[2]);
    }
    public override Expr<double> Access(Expr<Point3D> value, int idx) {
      return value.Bl()[idx];
    }
  }
  /// <summary>
  ///  Defines an x-, y-, and z-coordinate in 3-D space.
  /// </summary>
  public class Point3DBl : PointBl<Point3D, Point3DBl, Point3DArity> {
    public static implicit operator Point3DBl(Point3D d) { return (new Constant<Point3D>(d)); }
    public static implicit operator Point3DBl(Vector3D d) { return (new Constant<Point3D>((Point3D)d)); }
    public static implicit operator Point3DBl(Size3D d) { return (new Constant<Point3D>((Point3D)d)); }

    public static implicit operator Point3DBl(Expr<Point3D> v) { return new Point3DBl(v); }
    public static implicit operator Point3DBl(Expr<Vector3D> v) { return Point3DBl.ExplicitConvert(v); }
    public static implicit operator Point3DBl(Expr<Size3D> v) { return Point3DBl.ExplicitConvert(v); }
    public static implicit operator Point3DBl(PointBl p) { return new Point3DBl(p.X, p.Y, 0); }

    public static explicit operator PointBl(Point3DBl p) { return new PointBl(p.X, p.Y); }

    private Point3DBl(Expr<Point3D> Underlying) : base(Underlying) { }
    public Point3DBl(DoubleBl X, DoubleBl Y, DoubleBl Z) : base(Point3DArity.ArityExpr.Make(X, Y, Z)) { }
    public Point3DBl(PointBl XY, DoubleBl Z) : base(Point3DArity.ArityExpr.Make(XY.X, XY.Y, Z)) { }

    public static implicit operator Point3DBl(Random r) {
      return (Point3DBl)((TupleBl<Point3D, Point3DBl, Point3DArity>)r);
    }

    /// <summary>
    /// X/horizontal component of point.
    /// </summary>
    public DoubleBl X { get { return this[0]; } set { X.Bind = value; } }
    /// <summary>
    /// Y/horizontal component of point.
    /// </summary>
    public DoubleBl Y { get { return this[1]; } set { Y.Bind = value; } }
    /// <summary>
    /// Z/depth component of point.
    /// </summary>
    public DoubleBl Z { get { return this[2]; } set { Z.Bind = value; } }

    public override PointBl XY {
      get { return new PointBl(X, Y); }
      set { XY.Bind = value; }
    }

    /// <summary>
    /// Red component of point.
    /// </summary>
    public DoubleBl R { get { return X; } set { R.Bind = value; } }
    /// <summary>
    /// Green component of point.
    /// </summary>
    public DoubleBl G { get { return Y; } set { G.Bind = value; } }
    /// <summary>
    /// Blue component of point.
    /// </summary>
    public DoubleBl B { get { return Z; } set { B.Bind = value; } }

    static Point3DBl() {
      VectorType = typeof(Vector3D);

      Plus.Apply = (x, y) => x + ((Vector3D)y);
      Minus.Apply = (x, y) => x - ((Vector3D)y);
      MultiplyX.Apply = (x, y) => (Point3D)(((Vector3D)x) * y);
      DivideX.Apply = (x, y) => (Point3D)(((Vector3D)x) / y);
      Multiply.Apply = (p, q) => new Point3D(p.X * q.X, p.Y * q.Y, p.Z * q.Z);
      Divide.Apply = (p, q) => new Point3D(p.X / q.X, p.Y / q.Y, p.Z / q.Z);
      LengthOp.Apply = (p) => ((Vector3D)p).Length;
      Register(v => new Point3DBl(v));
      Negate.Expand = (p) => new Point3DBl(p.Bl().X * -1d, p.Bl().Y * -1d, p.Bl().Z * -1d);

      if (true) {
        DivideX.AsText = (a, b) => {
          var Type = typeof(Point3D).FullName;
          return ("new " + Type + "(" +
            a + ".X / " + b + ", " +
            a + ".Y / " + b + ", " +
            a + ".Z / " + b + ")");
        };
        MultiplyX.AsText = (a, b) => {
          var Type = typeof(Point3D).FullName;
          return ("new " + Type + "(" +
            a + ".X * " + b + ", " +
            a + ".Y * " + b + ", " +
            a + ".Z * " + b + ")");
        };
        Plus.AsText = (a, b) => {
          var Type = typeof(Point3D).FullName;
          return ("new " + Type + "(" +
            a + ".X + " + b + ".X, " +
            a + ".Y + " + b + ".Y, " +
            a + ".Z + " + b + ".Z)");
        };
      }
    }

    public static Point3D Plus0(Point3D p, double d) { return p + new Vector3D(d, d, d); }
    public static Point3D Minus0(Point3D p, double d) { return p - new Vector3D(d, d, d); }
    public static Point3D Mult(Point3D p0, Point3D p1) {
      return new Point3D(p0.X * p1.X, p0.Y * p1.Y, p0.Z * p1.Z);
    }
    public static Point3D Div(Point3D p0, Point3D p1) {
      return new Point3D(p0.X / p1.X, p0.Y / p1.Y, p0.Z / p1.Z);
    }
    public static Point3D Mod0(Point3D p0, Point3D p1) {
      return new Point3D(p0.X % p1.X, p0.Y % p1.Y, p0.Z % p1.Z);
    }

    public DoubleBl Dot(Point3DBl p) {
      return X * p.X + Y * p.Y + Z * p.Z;
    }
    public Point3DBl Cross(Point3DBl p) {
      return new Point3DBl(Y * p.Z - p.Y * Z, Z * p.X - X * p.Z, X * p.Y - p.X * Y);
    }
  }
  public partial class Point4DArity : ArityInfo<Point4D, Point4DArity> {
    public override string[] AccessorNames {
      get { return new string[] { "X", "Y", "Z", "W", }; }
    }
    public override int Arity {
      get { return 4; }
    }
    public override double[] ToArray(Point4D t) {
      return new double[] { t.X, t.Y, t.Z, t.W };
    }
    public override Point4D ToT(double[] values) {
      return new Point4D(values[0], values[1], values[2], values[3]);
    }
    public override Expr<double> Access(Expr<Point4D> value, int idx) {
      return value.Bl()[idx];
    }
  }
  /// <summary>
  /// Represents an x-, y-, z-, and w-coordinate point in world space used in performing
  ///    transformations with non-affine 3-D matrices.
  /// </summary>
  public class Point4DBl : PointBl<Point4D, Point4DBl, Point4DArity> {
    public static implicit operator Point4DBl(Point4D d) { return new Point4DBl(Operations.Make(d)); }
    private Point4DBl(Expr<Point4D> Underlying) : base(Underlying) { }
    public Point4DBl(DoubleBl X, DoubleBl Y, DoubleBl Z, DoubleBl W) : base(Point4DArity.ArityExpr.Make(X, Y, Z, W)) { }
    public Point4DBl(PointBl XY, PointBl ZW) : base(Point4DArity.ArityExpr.Make(XY.X, XY.Y, ZW.X, ZW.Y)) { }
    public DoubleBl X { get { return this[0]; } set { X.Bind = value; } }
    public DoubleBl Y { get { return this[1]; } set { Y.Bind = value; } }
    public DoubleBl Z { get { return this[2]; } set { Z.Bind = value; } }
    public DoubleBl W { get { return this[3]; } set { W.Bind = value; } }


    // swizzling
    public PointBl XX { get { return new PointBl(X, X); } set { XX.Bind = value; } }
    public PointBl YY { get { return new PointBl(Y, Y); } set { YY.Bind = value; } }
    public PointBl ZZ { get { return new PointBl(Z, Z); } set { ZZ.Bind = value; } }
    public PointBl XZ { get { return new PointBl(X, Z); } set { XZ.Bind = value; } }


    public override PointBl XY { get { return new PointBl(X, Y); } set { XY.Bind = value; } }
    public PointBl ZW { get { return new PointBl(Z, W); } set { ZW.Bind = value; } }

    public PointBl LeftTop { get { return XY; } set { LeftTop.Bind = value; } }
    public PointBl Size { get { return ZW; } set { Size.Bind = value; } }

    public static implicit operator Point4DBl(Expr<Rect> value) {
      return value.Map<Point4D>(r => new Point4D(r.Left, r.Top, r.Width, r.Height),
                                   p => new Rect(p.X, p.Y, p.Z, p.W));
    }

    static Point4DBl() {
      VectorType = typeof(Point4D);
      Plus.Apply = (x, y) => x + y;
      Minus.Apply = (x, y) => x - (y);
      Register(v => new Point4DBl(v));
    }
    public static Point4D Plus0(Point4D p, double d) { return p + new Point4D(d, d, d, d); }
    public static Point4D Minus0(Point4D p, double d) { return p - new Point4D(d, d, d, d); }
    public static Point4D Mult(Point4D p0, Point4D p1) {
      return new Point4D(p0.X * p1.X, p0.Y * p1.Y, p0.Z * p1.Z, p0.W * p1.W);
    }
    public static Point4D Div(Point4D p0, Point4D p1) {
      return new Point4D(p0.X / p1.X, p0.Y / p1.Y, p0.Z / p1.Z, p0.W / p1.W);
    }
    public static Point4D Mod0(Point4D p0, Point4D p1) {
      return new Point4D(p0.X % p1.X, p0.Y % p1.Y, p0.Z % p1.Z, p0.W % p1.W);
    }


    public static implicit operator Point4DBl(Expr<Point4D> v) { return new Point4DBl(v); }
  }
  public partial class ColorArity : ArityInfo<Color, ColorArity> {
    public override int Arity {
      get { return 4; }
    }

    public override string[] AccessorNames {
      get { return new string[] { "ScA", "ScR", "ScG", "ScB" }; }
    }

    public override double[] ToArray(Color t) {
      return new double[] { t.ScA, t.ScR, t.ScG, t.ScB };
    }
    public override Color ToT(double[] values) {
      return Color.FromScRgb((float)values[0], (float)values[1], (float)values[2], (float)values[3]);
    }
    public override Expr<double> Access(Expr<Color> value, int idx) {
      return value.Bl()[idx];
    }
  }
  /// <summary>
  ///  Describes a color in terms of alpha, red, green, and blue channels.
  /// </summary>
  public partial class ColorBl : TupleBl<Color, ColorBl, ColorArity> {
    // not a real tuple.
    private ColorBl(Expr<Color> Underlying) : base(Underlying) { }

    static ColorBl() {
      Plus.Apply = (x, y) => x + y;
      Minus.Apply = (x, y) => x - y;
      MultiplyX.Apply = (x, y) => {
        var ret = Color.Multiply(x, (float)y);
        return ret;
      };
      DivideX.Apply = (x, y) => Color.Multiply(x, 1f / (float)y);
      ClampOp.Apply = (c, min, max) => c.Clamp(min, max);
      var nms = Arity.AccessorNames;
      for (int i = 0; i < Accessors.Length; i++) {
        var ii = i;
        Accessors[ii].Shader = c => c + "." + nms[ii].Substring(nms[ii].Length - 1, 1).ToLower();
      }
      MultiplyX.Linq = (e1, e2) => linq.Expression.Multiply(e1, linq.Expression.Convert(e2, typeof(float)));
      DivideX.Linq = (e1, e2) => linq.Expression.Multiply(e1,
        linq.Expression.Divide(linq.Expression.Constant(1f, typeof(float)),
                               linq.Expression.Convert(e2, typeof(float))));

      Register(v => new ColorBl(v));
    }
    /// <summary>
    /// Creates a new System.Windows.Media.Color structure by using the specified
    ///     ScRGB alpha channel and color channel values.
    /// </summary>
    /// <param name="a">The ScRGB alpha channel.</param>
    /// <param name="r">The ScRGB red channel.</param>
    /// <param name="g">The ScRGB green channel.</param>
    /// <param name="b">The ScRGB blue channel.</param>
    /// <returns>Color structure with the specified values.</returns>
    public static ColorBl FromScRGB(DoubleBl a, DoubleBl r, DoubleBl g, DoubleBl b) {
      return new ColorBl(ColorArity.ArityExpr.Make(a, r, g, b));
    }
    /// <summary>     
    /// Creates a new System.Windows.Media.Color structure by using the specified
    ///     ScRGB alpha channel and color channel values.
    /// </summary>
    public static ColorBl FromScRGB(DoubleBl a, Point3DBl rgb) {
      return new ColorBl(ColorArity.ArityExpr.Make(a, rgb.R, rgb.G, rgb.B));
    }

    // for swizzling
    public static explicit operator Point4DBl(ColorBl color) {
      return new Point4DBl(color.ScR, color.ScG, color.ScB, color.ScA);
    }



    /// <summary>
    /// Gets or sets the ScRGB alpha channel value of the color.
    /// </summary>
    public DoubleBl ScA { get { return this[0]; } }
    /// <summary>
    /// Gets or sets the ScRGB red channel value of the color.
    /// </summary>
    public DoubleBl ScR { get { return this[1]; } }
    /// <summary>
    /// Gets or sets the ScRGB green channel value of the color.
    /// </summary>
    public DoubleBl ScG { get { return this[2]; } }
    /// <summary>
    /// Gets or sets the ScRGB blue channel value of the color.
    /// </summary>
    public DoubleBl ScB { get { return this[3]; } }

    /// <summary>
    /// Gets or sets the three ScRGB color channels value of the color.
    /// </summary>
    public Point3DBl ScRGB { get { return new Point3DBl(ScR, ScG, ScB); } set { ScRGB.Bind = value; } }

    public static implicit operator ColorBl(Expr<Color> v) { return new ColorBl(v); }
    public static implicit operator ColorBl(Color v) { return Operations.Make(v); }
  }
  /// <summary>
  /// Bling wrapper around a WPF collection of primitives.
  /// </summary>
  /// <typeparam name="E">Collection element type.</typeparam>
  /// <typeparam name="EBRAND">Bling type of collection element.</typeparam>
  /// <typeparam name="T">Original collection type.</typeparam>
  /// <typeparam name="BRAND">Bling type of collection.</typeparam>
  public abstract class PrimitiveCollectionBl<E, EBRAND, T, BRAND> : CollectionBl<E, EBRAND, T, BRAND>
    where BRAND : PrimitiveCollectionBl<E, EBRAND, T, BRAND>
    where T : Freezable, IFormattable, IList, ICollection, IList<E>, ICollection<E>, IEnumerable<E>, IEnumerable, new()
    where EBRAND : Brand<E, EBRAND>
    where E : new() {
    public PrimitiveCollectionBl(Expr<T> Underlying) : base(Underlying) { }

    /// <summary>
    ///     Makes the current object unmodifiable and sets its System.Windows.Freezable.IsFrozen
    ///     property to true.
    /// </summary>
    public void Freeze() {
      CurrentValue.Freeze();
    }
    /// <summary>
    /// Gets a value that indicates whether the object is currently modifiable.
    /// </summary>
    public BoolBl IsFrozen { get { return Underlying.Map<bool>(t => t.IsFrozen); } }

    /// <summary>
    /// Gets a value that indicates whether the object can be made unmodifiable.
    /// </summary>
    public BoolBl CanFreeze { get { return Underlying.Map<bool>(t => t.CanFreeze); } }

    private linq.Expression AssignElements(linq.Expression currentBuffer, IList<EBRAND> Backing) {
      List<linq.Expression> statements = new List<linq.Expression>();
      var eval = new Bling.Linq.DefaultLinqEval(null);
      for (int i = 0; i < Backing.Count; i++) {
        var properties = typeof(IList<E>).GetProperties();
        var indexP = typeof(IList<E>).GetProperty("Item");

        var bufferAt = linq.Expression.Property(currentBuffer, indexP, linq.Expression.Constant(i, typeof(int)));
        eval.PushScope();
        var assignTo = ((Bling.Linq.DefaultLinqEval.MyInfo<E>)Backing[i].Underlying.Eval(eval)).Value;
        var assignElem = linq.Expression.Assign(bufferAt, assignTo);
        statements.Add(eval.PopScope(assignElem));
      }
      return linq.Expression.Block(statements);
    }
    /// <summary>
    /// Bind this value to a new populated primitive collection.
    /// </summary>
    /// <param name="Backing">Elements to populate the new primitive collection.</param>
    public void InitElements(IList<EBRAND> Backing) {
      T Buf = new T();
      for (int i = 0; i < Backing.Count; i++) {
        Buf.Add(Backing[i].CurrentValue);
      }
      this.Now = ToBrand(new Constant<T>(Buf));
    }
    public Action RefreshAction(Func<IntBl, Expr<E>> F, int Count) {
      T[] Buffers = new T[2];
      Action[] Set = new Action[2];
      for (int i = 0; i < 2; i++) {
        Buffers[i] = new T();
        for (int j = 0; j < Count; j++) {
          Buffers[i].Add(new E());
        }
        Set[i] = PrimitiveCollectionBl<E, EBRAND, T, BRAND>.Assign(this, ToBrand(new Constant<T>(Buffers[i])));
      }
      int BufIndex = 0;
      Action Set0 = () => {
        Set[BufIndex]();
        BufIndex = (BufIndex + 1) % 2;
      };
      Func<T> Current0 = () => Buffers[BufIndex];
      List<linq.Expression> statements = new List<linq.Expression>();

      var currentBuffer = linq.Expression.Parameter(typeof(T), "CurrentBuffer");
      var assignBuffer = linq.Expression.Assign(currentBuffer,
        linq.Expression.Invoke(linq.Expression.Constant(Current0, typeof(Func<T>))));
      statements.Add(assignBuffer);
      {
        var eval = new Bling.Linq.DefaultLinqEval(null);
        var loop = eval.For("i", Count, (i) => {
          var I = new Bling.Linq.LinqValue<int>(i.Value);
          var assignTo = ((Bling.Linq.DefaultLinqEval.MyInfo<E>)F(I).Eval(eval)).Value;
          var properties = typeof(IList<E>).GetProperties();
          var indexP = typeof(IList<E>).GetProperty("Item");
          var bufferAt = linq.Expression.Property(currentBuffer, indexP, i.Value);
          var assignElem = linq.Expression.Assign(bufferAt, assignTo);
          return assignElem;
        });
        statements.Add(loop);
      }
      statements.Add(linq.Expression.Invoke(linq.Expression.Constant(Set0, typeof(Action))));
      var doit = linq.Expression.Lambda<Action>(linq.Expression.Block(new linq.ParameterExpression[] { currentBuffer }, statements));
      var doitF = doit.Compile();
      return doitF;
    }

    /*
    public linq.Expression DoAssign<EVAL>(Bling.Linq.LinqEval<EVAL> eval) {


    }*/

    /// <summary>
    /// Creates an efficient swap collection refresh action. When the resulting action is called, a
    /// collection is efficiently re-populated via Backing and bound to this value.
    /// </summary>
    /// <param name="Backing">Elements to populate collection on refresh.</param>
    /// <returns>An action that refreshes the collection bound to this value.</returns>
    public Action RefreshAction(IList<EBRAND> Backing) {
      T[] Buffers = new T[2];
      Action[] Set = new Action[2];
      for (int i = 0; i < 2; i++) {
        Buffers[i] = new T();
        for (int j = 0; j < Backing.Count; j++) {
          Buffers[i].Add(new E());
        }
        Set[i] = PrimitiveCollectionBl<E, EBRAND, T, BRAND>.Assign(this, ToBrand(new Constant<T>(Buffers[i])));
      }
      int BufIndex = 0;
      Action Set0 = () => {
        Set[BufIndex]();
        BufIndex = (BufIndex + 1) % 2;
      };
      Func<T> Current0 = () => Buffers[BufIndex];
      List<linq.Expression> statements = new List<linq.Expression>();

      var currentBuffer = linq.Expression.Parameter(typeof(T), "CurrentBuffer");
      var assignBuffer = linq.Expression.Assign(currentBuffer,
        linq.Expression.Invoke(linq.Expression.Constant(Current0, typeof(Func<T>))));
      statements.Add(assignBuffer);
      statements.Add(AssignElements(currentBuffer, Backing));
      statements.Add(linq.Expression.Invoke(linq.Expression.Constant(Set0, typeof(Action))));
      var doit = linq.Expression.Lambda<Action>(linq.Expression.Block(new linq.ParameterExpression[] { currentBuffer }, statements));
      var doitF = doit.Compile();
      return doitF;
    }
  }
  public class PointCollectionBl : PrimitiveCollectionBl<Point, PointBl, PointCollection, PointCollectionBl> {
    public PointCollectionBl(Expr<PointCollection> Underlying) : base(Underlying) { }
    public PointCollectionBl() : this(new Constant<PointCollection>(new PointCollection())) { }
    public static implicit operator PointCollectionBl(Expr<PointCollection> target) { return new PointCollectionBl((target)); }
    public static implicit operator PointCollectionBl(PointCollection target) { return (new Constant<PointCollection>(target)); }
    static PointCollectionBl() { Register(v => v); }
  }
  public class IntCollectionBl : PrimitiveCollectionBl<int, IntBl, Int32Collection, IntCollectionBl> {
    public IntCollectionBl(Expr<Int32Collection> Underlying) : base(Underlying) { }
    public IntCollectionBl() : this(new Constant<Int32Collection>(new Int32Collection())) { }
    public static implicit operator IntCollectionBl(Expr<Int32Collection> target) { return new IntCollectionBl((target)); }
    public static implicit operator IntCollectionBl(Int32Collection target) { return (new Constant<Int32Collection>(target)); }
    static IntCollectionBl() { Register(v => v); }
  }

  public class DoubleCollectionBl : PrimitiveCollectionBl<double, DoubleBl, DoubleCollection, DoubleCollectionBl> {
    public DoubleCollectionBl(Expr<DoubleCollection> Underlying) : base(Underlying) { }
    public DoubleCollectionBl() : this(new Constant<DoubleCollection>(new DoubleCollection())) { }
    public static implicit operator DoubleCollectionBl(Expr<DoubleCollection> target) { return new DoubleCollectionBl((target)); }
    public static implicit operator DoubleCollectionBl(DoubleCollection target) { return (new Constant<DoubleCollection>(target)); }
    static DoubleCollectionBl() { Register(v => v); }
  }
  public abstract class BasePoint3DCollectionBl<E, EBRAND, T, BRAND> : PrimitiveCollectionBl<E, EBRAND, T, BRAND>
    where BRAND : PrimitiveCollectionBl<E, EBRAND, T, BRAND>
    where T : Freezable, IFormattable, IList, ICollection, IList<E>, ICollection<E>, IEnumerable<E>, IEnumerable, new()
    where EBRAND : Brand<E, EBRAND>
    where E : new() {
    protected abstract Point3DBl ConvertA(EBRAND Orig);
    protected abstract EBRAND ConvertB(Point3DBl Orig);



    public BasePoint3DCollectionBl(Expr<T> Underlying) : base(Underlying) { }
    /*
    public static implicit operator Vector3DCollectionBl(Value<Vector3DCollection> target) { return new Vector3DCollectionBl((target)); }
    public static implicit operator Vector3DCollectionBl(Vector3DCollection target) { return (new Constant<Vector3DCollection>(target)); }
    */
  }


  public class Point3DCollectionBl : BasePoint3DCollectionBl<Point3D, Point3DBl, Point3DCollection, Point3DCollectionBl> {
    public Point3DCollectionBl(Expr<Point3DCollection> Underlying) : base(Underlying) { }
    public Point3DCollectionBl() : this(new Constant<Point3DCollection>(new Point3DCollection())) { }
    public static implicit operator Point3DCollectionBl(Expr<Point3DCollection> target) { return new Point3DCollectionBl((target)); }
    public static implicit operator Point3DCollectionBl(Point3DCollection target) { return (new Constant<Point3DCollection>(target)); }
    static Point3DCollectionBl() { Register(v => v); }
    protected override Point3DBl ConvertA(Point3DBl Orig) { return Orig; }
    protected override Point3DBl ConvertB(Point3DBl Orig) { return Orig; }
  }
  public class Vector3DBl : Brand<Vector3D, Vector3DBl> {
    public Vector3DBl(Expr<Vector3D> Underlying) : base(Underlying) { }
    public static implicit operator Point3DBl(Vector3DBl v) { return v.Underlying; }
    public static implicit operator Vector3DBl(Point3DBl v) { return Vector3DBl.ExplicitConvert(v.Underlying); }
  }
  public class Vector3DCollectionBl : BasePoint3DCollectionBl<Vector3D, Vector3DBl, Vector3DCollection, Vector3DCollectionBl>, PrimitiveCollectionBl<Point3D, Point3DBl> {
    public Vector3DCollectionBl(Expr<Vector3DCollection> Underlying) : base(Underlying) { }
    public Vector3DCollectionBl() : this(new Constant<Vector3DCollection>(new Vector3DCollection())) { }
    public static implicit operator Vector3DCollectionBl(Expr<Vector3DCollection> target) { return new Vector3DCollectionBl((target)); }
    public static implicit operator Vector3DCollectionBl(Vector3DCollection target) { return (new Constant<Vector3DCollection>(target)); }
    static Vector3DCollectionBl() { Register(v => v); }
    protected override Point3DBl ConvertA(Vector3DBl Orig) { return Orig; } // Point3DBl.Coerce<Vector3D>(Orig); }
    protected override Vector3DBl ConvertB(Point3DBl Orig) { return Orig; }

    public new IList<Point3DBl> AddMany {
      set {
        var list = new Vector3DBl[value.Count];
        for (int i = 0; i < 0; i++) list[i] = value[i];
        base.AddMany = list;
      }
    }
    public void Add(params Point3DBl[] value) {
      var list = new Vector3DBl[value.Length];
      for (int i = 0; i < 0; i++) list[i] = value[i];
      Add(list);
    }
    public new Point3DBl AddOne { set { base.AddOne = value; } }
    public void InitElements(IList<Point3DBl> value) {
      var list = new Vector3DBl[value.Count];
      for (int i = 0; i < 0; i++) list[i] = value[i];
      InitElements(list);
    }
    public Action RefreshAction(IList<Point3DBl> value) {
      var list = new Vector3DBl[value.Count];
      for (int i = 0; i < 0; i++) list[i] = value[i];
      return RefreshAction(list);
    }
  }
  public static partial class BlExtensions {
    /// <summary>
    /// Convert unbranded Bl value to branded Bl value.
    /// </summary>
    /// <param name="d">Unbranded Bl value.</param>
    /// <returns>Branded Bl value.</returns>
    public static PointBl Bl(this Expr<Point> d) { return d; }
    /// <summary>
    /// Convert unbranded Bl value to branded Bl value.
    /// </summary>
    /// <param name="d">Unbranded Bl value.</param>
    /// <returns>Branded Bl value.</returns>
    public static Point3DBl Bl(this Expr<Point3D> d) { return d; }
    /// <summary>
    /// Convert unbranded Bl value to branded Bl value.
    /// </summary>
    /// <param name="d">Unbranded Bl value.</param>
    /// <returns>Branded Bl value.</returns>
    public static Point4DBl Bl(this Expr<Point4D> d) { return d; }
    /// <summary>
    /// Convert unbranded Bl value to branded Bl value.
    /// </summary>
    /// <param name="d">Unbranded Bl value.</param>
    /// <returns>Branded Bl value.</returns>
    public static ColorBl Bl(this Expr<Color> d) { return d; }
    /// <summary>
    /// Convert unbranded Bl value to branded Bl value.
    /// </summary>
    /// <param name="d">Unbranded Bl value.</param>
    /// <returns>Branded Bl value.</returns>
    public static BrushBl Bl(this Expr<Brush> d) { return d; }


    public static ColorBl Condition(this bool b, ColorBl ifTrue, ColorBl ifFalse) {
      return b.Bl().Condition(ifTrue, ifFalse);
    }
    public static Point3DBl Condition(this bool b, Point3DBl ifTrue, Point3DBl ifFalse) {
      return b.Bl().Condition(ifTrue, ifFalse);
    }
    public static DoubleBl Condition(this bool b, DoubleBl ifTrue, DoubleBl ifFalse) {
      return b.Bl().Condition(ifTrue, ifFalse);
    }

    public static Func<IntBl, PointBl> Bl(this Func<IntBl, Expr<Point>> F) { return x => F(x).Bl(); }
    public static Func<IntBl, Point3DBl> Bl(this Func<IntBl, Expr<Point3D>> F) { return x => F(x).Bl(); }
    public static Func<IntBl, ColorBl> Bl(this Func<IntBl, Expr<Color>> F) { return x => F(x).Bl(); }
    public static Func<IntBl, BrushBl> Bl(this Func<IntBl, Expr<Brush>> F) { return x => F(x).Bl(); }
    /// <summary>
    /// Convert core language value to branded Bl value.
    /// </summary>
    /// <param name="d">Core language value.</param>
    /// <returns>Branded Bl value.</returns>
    public static PointBl Bl(this Point d) { return d; }
    /// <summary>
    /// Convert core language value to branded Bl value.
    /// </summary>
    /// <param name="d">Core language value.</param>
    /// <returns>Branded Bl value.</returns>
    public static ColorBl Bl(this Color d) { return d; }
    /// <summary>
    /// Convert core language value to branded Bl value.
    /// </summary>
    /// <param name="d">Core language value.</param>
    /// <returns>Branded Bl value.</returns>
    public static BrushBl Bl(this Brush d) { return d; }

  }

}
